package dw.common;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.MatchMode;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public abstract class GenericDaoImpl<T, I extends Serializable> extends
    HibernateDaoSupport implements GenericDao<T, I> {

  /**
   * The class of the pojo being persisted.
   */
  private Class<? extends T> clazz;

  public GenericDaoImpl() {
    this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
        .getActualTypeArguments()[0];
  }

  @SuppressWarnings("unchecked")
  public T findById(I id) {
    return (T) getHibernateTemplate().load(clazz, id);
  }

  @SuppressWarnings("unchecked")
  public List<T> findByExample(final T t) {
    return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
      public Object doInHibernate(Session session) {
        Example ex = Example.create(t).ignoreCase().enableLike(MatchMode.ANYWHERE);
        return session.createCriteria(clazz).add(ex).list();
      }
    });
  }

  @SuppressWarnings("unchecked")
  public List<T> findAll() {
    return getHibernateTemplate().loadAll(clazz);
  }

  @SuppressWarnings("unchecked")
  public List<T> findByIds(final String propertyNameOfId, List<I> collectionOfIds) {
    final Set<I> idSet = new HashSet<I>();
    idSet.addAll(collectionOfIds);
    return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
      public Object doInHibernate(Session session) {
        Criteria queryCriteria = session.createCriteria(clazz);
        queryCriteria.add(Expression.in(propertyNameOfId, idSet));
        return queryCriteria.list();
      }
    });
  }

  public void delete(I id) {
    delete(findById(id));
  }

  public void delete(T t) {
    getHibernateTemplate().delete(t);
  }

  public void saveOrUpdate(T t) {
    getHibernateTemplate().saveOrUpdate(t);
  }
}